<template>
  <a-card :bordered="false" :bodyStyle="{ padding: '0' }">
    <a-spin :spinning="treeLoading">
      <div class="custom-col" :style="{ minHeight: `${layoutContentHeight - pageHeaderHeight}px` }">
        <div class="custom-col-left resizable">
          <span class="resizable-handler-right"></span>
          <a-tree
            class="tree--custom"
            :class="{ 'has-menu': $auth('add,delete,edit', $route.meta.permissionId) }"
            blockNode
            :expandedKeys.sync="expandedKeys"
            :treeData="treeData"
            :replaceFields="replaceFields"
            :selectedKeys="selectedOrg"
            @select="onSelectTreeNode"
          >
            <template slot="title" slot-scope="scopeProps">
              <div class="tree--custom-node">
                <div class="tree--custom-node-text" :title="scopeProps[UserPickerOptions.partyProp]">
                  {{ scopeProps[UserPickerOptions.partyProp] }}
                </div>
                <div class="tree--custom-node-menu" v-action:add|delete|edit>
                  <a-dropdown :trigger="['hover']" overlayClassName="tree--custom-node-menu-dropdowm">
                    <a
                      class="ant-dropdown-link"
                      href="javascript:;"
                    ><a-icon type="more" :style="{ fontSize: '20px' }" />
                    </a>
                    <a-menu slot="overlay" @click="({ key }) => handlePartyActions(key, scopeProps)">
                      <a-menu-item key="add" v-action:add>
                        <a-icon class="ant-dropdown-link-icon" type="plus" />
                        {{ $t('authenticationCenter.org.newSubOrg') }}
                      </a-menu-item>
                      <a-menu-item
                        v-action:edit
                        key="edit"
                        :disabled="scopeProps[UserPickerOptions.pid] === UserPickerOptions.root"
                      >
                        <a-icon class="ant-dropdown-link-icon" type="edit" />
                        {{ $t('authenticationCenter.org.editOrg') }}
                      </a-menu-item>
                      <a-menu-item
                        v-action:delete
                        key="delete"
                        :disabled="scopeProps[UserPickerOptions.pid] === UserPickerOptions.root"
                      >
                        <a-icon class="ant-dropdown-link-icon" type="delete" />
                        {{ $t('authenticationCenter.org.deleteOrg') }}
                      </a-menu-item>
                      <a-menu-item
                        v-action:edit
                        key="moveup"
                        :disabled="scopeProps[UserPickerOptions.pid] === UserPickerOptions.root || scopeProps.isFirst"
                      >
                        <a-icon class="ant-dropdown-link-icon" type="up" /> {{ $t('common.moveUp') }}
                      </a-menu-item>
                      <a-menu-item
                        v-action:edit
                        key="movedown"
                        :disabled="scopeProps[UserPickerOptions.pid] === UserPickerOptions.root || scopeProps.isLast"
                      >
                        <a-icon class="ant-dropdown-link-icon" type="down" /> {{ $t('common.moveDown') }}
                      </a-menu-item>
                    </a-menu>
                  </a-dropdown>
                </div>
              </div>
            </template>
          </a-tree>
        </div>
        <div class="custom-col-right">
          <a-card :bordered="false">
            <div class="table-page-search-wrapper">
              <a-form layout="inline">
                <a-row :gutter="16">
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('authenticationCenter.org.personName')">
                      <a-input v-model="queryParams.name" allowClear />
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('authenticationCenter.org.username')">
                      <a-input v-model="queryParams.username" allowClear />
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('authenticationCenter.org.jobNumber')">
                      <a-input v-model="queryParams.jobNumber" allowClear />
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('authenticationCenter.org.mobile')">
                      <a-input placeholder="" v-model="queryParams.mobile" allowClear />
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('authenticationCenter.org.email')">
                      <a-input placeholder="" v-model="queryParams.email" allowClear />
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <a-form-item :label="$t('common.status')">
                      <a-select v-model="queryParams.status">
                        <a-select-option value="">{{ $t('common.all') }}</a-select-option>
                        <a-select-option :value="1">{{ $t('authenticationCenter.org.inservice') }}</a-select-option>
                        <a-select-option :value="2">{{ $t('authenticationCenter.org.resigned') }}</a-select-option>
                      </a-select>
                    </a-form-item>
                  </a-col>
                  <a-col :md="6" :sm="24">
                    <span
                      class="table-page-search-submitButtons"
                      :style="(advanced && { float: 'right', overflow: 'hidden' }) || {}"
                    >
                      <a-button type="primary" @click="$refs.table.refresh(true)">{{ $t('common.query') }}</a-button>
                      <a-button style="margin-left: 8px" @click="resetSearch">{{ $t('common.reset') }}</a-button>
                    </span>
                  </a-col>
                </a-row>
              </a-form>
            </div>
            <div class="table-operator">
              <a-button v-action:add type="primary" icon="plus" @click="handleCreateUser">{{
                $t('button.add')
              }}</a-button>
              <a-button type="primary" icon="setting" @click="$refs.fieldConfig.open()">
                {{ $t('button.fieldConfig') }}
              </a-button>
              <a-button-group v-action:import>
                <a-upload
                  name="file"
                  accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
                  :show-upload-list="false"
                  :disabled="uploading"
                  :customRequest="customRequest"
                  @change="handleUpload"
                >
                  <a-button
                    type="primary"
                    icon="import"
                    :loading="uploading"
                    :disabled="!treeLoading && selectedOrg.length === 0"
                    style="border-top-left-radius: 4px; border-bottom-left-radius: 4px;"
                  >{{ $t('common.import') }}</a-button
                  >
                </a-upload>
                <a-button
                  type="primary"
                  title="导入模板下载"
                  icon="download"
                  :disabled="!treeLoading && selectedOrg.length === 0"
                  @click="downloadExcelTemplate"
                />
              </a-button-group>
              <a-button
                v-action:export
                type="primary"
                icon="export"
                :loading="exporting"
                :disabled="!treeLoading && selectedOrg.length === 0"
                @click="handleExportUsers"
              >
                {{ $t('common.export') }}
              </a-button>
              <a-dropdown v-action:resign|delete|resetPw|transferDept>
                <a-button>{{ $t('common.batchActions') }} <a-icon type="down"/></a-button>
                <a-menu slot="overlay" @click="handleUserActions">
                  <a-menu-item
                    v-action:resign
                    key="quit"
                    :disabled="selectedRowKeys.length === 0 || batchStatus.hasLeaved"
                  >
                    <a-icon type="user-delete" />
                    {{ $t('authenticationCenter.org.resign') }}
                  </a-menu-item>
                  <a-menu-item v-action:delete key="delete" :disabled="selectedRowKeys.length === 0">
                    <a-icon type="delete" />
                    {{ $t('common.delete') }}
                  </a-menu-item>
                  <a-menu-item
                    v-action:resetPw
                    key="password"
                    :disabled="selectedRowKeys.length === 0 || batchStatus.hasLeaved"
                  >
                    <a-icon type="lock" />
                    {{ $t('authenticationCenter.org.resetPw') }}
                  </a-menu-item>
                  <a-menu-item
                    v-action:transferDept
                    key="move"
                    :disabled="selectedRowKeys.length === 0 || batchStatus.hasLeaved || batchStatus.orgExcepted"
                  >
                    <a-icon type="drag" />
                    {{ $t('authenticationCenter.org.transferDept') }}
                  </a-menu-item>
                </a-menu>
              </a-dropdown>
            </div>
            <s-table
              v-if="selectedOrg.length > 0"
              ref="table"
              size="default"
              rowKey="id"
              :columns="columns"
              :data="loadData"
              :alert="$auth('add,delete,edit', $route.meta.permissionId) ? options.alert : null"
              :rowSelection="$auth('add,delete,edit', $route.meta.permissionId) ? options.rowSelection : null"
              :showPagination="true"
              :scroll="{ x: true }"
            >
              <span slot="name" slot-scope="text, record">
                <router-link v-if="record.status === 1" :to="{ name: 'structureUserInfo', params: { id: record.id } }">
                  <span :title="text">{{ text }}</span>
                </router-link>
                <span v-else :title="text">{{ text }}</span>
              </span>
              <span slot="status" slot-scope="text">
                <a-badge :status="text | userStatusColorFilter" />
                <span>{{ text | userStatusFilter }}</span>
              </span>
              <span slot="action" slot-scope="text, record" class="actionsList">
                <a
                  v-action:sort
                  :disabled="record.status !== 1"
                  href="javascript:;"
                  @click="handleSortUser(record.id, record.serialNum)"
                >{{ $t('common.sort') }}</a
                >
                <a-divider v-action:edit type="vertical" />
                <a
                  v-action:edit
                  :disabled="record.status !== 1"
                  href="javascript:;"
                  @click="handleUpdateUser(record.id)"
                >{{ $t('common.edit') }}</a
                >
                <a-divider v-action:delete type="vertical" />
                <a-popconfirm
                  :title="$t('common.delWarning', { name: $t('common.staff') })"
                  @confirm="handleDeleteUsers(record.id)"
                  :okText="$t('common.ok')"
                  :cancelText="$t('common.cancel')"
                >
                  <a v-action:delete href="#" class="link-danger">{{ $t('common.delete') }}</a>
                </a-popconfirm>
              </span>
            </s-table>
          </a-card>
        </div>
      </div>
    </a-spin>
    <template v-if="selectedOrg.length > 0">
      <!-- 新建、编辑部门 -->
      <org-form ref="orgForm" :partyList="partyList" @ok="handleOrgSubmit" />
      <!-- 初步导入人员结果 -->
      <import-result-modal
        ref="importResultModal"
        :fieldMap="{ name: 'name', targetId: 'orgId' }"
        :confirmUpload="importConfirmUsers"
        @ok="handleImportSuccess"
      />
      <!-- 人员排序 -->
      <user-sort ref="userSort" :orgId="this.selectedOrg[0]" @ok="$refs.table.refresh()" />
      <!-- 人员移动 -->
      <user-move ref="userMove" :orgId="this.selectedOrg[0]" :partyList="partyList" @ok="handleClearBatch" />
    </template>
    <!-- 字段显示 -->
    <field-config
      ref="fieldConfig"
      title="title"
      dataIndex="dataIndex"
      :fields="dynamicFields"
      :selectedKeys="visibleFields"
      :loading="fieldsLoading"
      @ok="handleFields"
    />
  </a-card>
</template>

<script>
import { STable, ResizableGrid, FieldConfig } from '@/components'
import { OrgForm, UserSort, UserMove } from './modules'
import ImportResultModal from '@/widgets/ImportResultModal'
import { dynamicFields, constantFields } from './data'
import { readTableFields, updateTableFields } from '@/api/common'
import {
  readAllOrg,
  readUsers,
  deleteOrg,
  moveUpOrg,
  moveDownOrg,
  deleteUser,
  quitUser,
  exportUsers,
  resetUserPassword,
  importUsers,
  importConfirmUsers
} from '@/api/authenticationCenter/structure'
import { UserPickerOptions } from '@/components/UserPicker/options'
import { setArrayToTree, downloadFileStream, downloadFile, getQueryParams, getNodeById } from '@/utils/util'
import { layoutMixin, tableSearchFormMixin, resizableMixin } from '@/utils/mixin'

const initialqueryParams = {
  name: '',
  jobNumber: '',
  username: '',
  status: 1,
  telephone: '',
  mobile: '',
  email: ''
}

export default {
  name: 'StructureList',
  mixins: [layoutMixin, tableSearchFormMixin, resizableMixin],
  components: {
    STable,
    ResizableGrid,
    FieldConfig,
    OrgForm,
    ImportResultModal,
    UserSort,
    UserMove
  },
  data () {
    return {
      initFlag: true,
      treeLoading: true,
      replaceFields: {
        children: UserPickerOptions.collection,
        title: 'name',
        key: UserPickerOptions.id
      },
      partyList: [],
      expandedKeys: [],
      selectedOrg: [],
      selectedOrgName: '',
      UserPickerOptions,
      pageParams: {},
      queryParams: { ...initialqueryParams },
      // 获取表格显示字段
      fieldsLoading: true,
      dynamicFields,
      visibleFields: [],
      // 加载数据方法 必须为 Promise 对象
      loadData: params => {
        if (this.selectedOrg.length === 0) return false
        // 如果是首次加载，则pageParams里的参数优先级高；如果不是首次加载，则params里的参数优先级高
        const req = this.initFlag
          ? {
            ...params,
            ...this.queryParams
          }
          : {
            ...this.queryParams,
            ...params
          }
        req.id = this.selectedOrg[0]

        // 表格数据加载完成后会有路由跳转，此时新增人员等同样导致页面跳转的按钮需要禁用
        this.tableLoaded = false
        return readUsers(req).then(res => {
          this.initFlag && (this.initFlag = false)
          this.pageParams = req
          this.$router.push({
            ...this.$route,
            query: {
              ...params,
              ...getQueryParams(this.queryParams)
            },
            params: {
              orgId: req.id
            }
          })
          this.tableLoaded = true
          return res.data
        })
      },
      // 表格数据是否加载完
      tableLoaded: false,
      selectedRowKeys: [],
      selectedRows: [],
      // custom table alert & rowSelection
      options: {
        alert: {
          show: true,
          clear: () => {
            this.selectedRowKeys = []
            this.selectedRows = []
          }
        },
        rowSelection: {
          selectedRowKeys: this.selectedRowKeys,
          onChange: this.onSelectChange
        }
      },
      optionAlertShow: false,
      // 导入导出
      uploading: false,
      exporting: false,
      importConfirmUsers
    }
  },
  computed: {
    treeData () {
      const partyList = [...this.partyList]
      partyList.forEach(party => {
        party.scopedSlots = { title: 'title' }
      })

      // 组织机构部门树状结构
      const tree = setArrayToTree({
        ...UserPickerOptions,
        data: partyList
      })

      return tree
    },
    // 表格显示字段
    columns () {
      const fields = this.visibleFields.map(key => {
        return dynamicFields.find(item => item.dataIndex === key)
      })
      // 根据权限去掉子表格操作栏
      if (!this.$auth('delete,edit', this.$route.meta.permissionId)) return [...fields]

      return [...fields, ...constantFields]
    },
    // 批量选择人员中是否有离职的、非当前部门的人员
    batchStatus () {
      return {
        hasLeaved: this.selectedRows.some(item => item.status !== 1),
        orgExcepted: this.selectedRows.some(item => !item.orgIds.includes(this.selectedOrg[0]))
      }
    }
  },
  mounted () {
    this.getAllParty()
    this.getTableFields()
  },
  methods: {
    // 获取表格字段
    async getTableFields () {
      const res = await readTableFields({
        table: 'mos_user'
      })
      this.fieldsLoading = false
      if (res.code === 'sso.ok') {
        this.visibleFields = res.data.checkedFields
      }
    },
    // 获取所有部门
    async getAllParty () {
      const res = await readAllOrg()
      this.treeLoading = false
      if (res.code === 'sso.ok') {
        this.partyList = res.data || []
        if (this.selectedOrg.length === 0 && this.partyList.length > 0) {
          this.selectedOrg = [this.partyList[0].id]
          this.selectedOrgName = this.partyList[0].name
        }
        if (this.expandedKeys.length === 0) {
          this.expandedKeys = [this.partyList[0].id]
        }
      }
    },
    // 部门操作权限
    handlePartyActions (key, party) {
      switch (key) {
        case 'add':
          this.$refs.orgForm.add(party)
          break
        case 'edit':
          this.$refs.orgForm.edit(party)
          break
        case 'delete':
          this.$confirm({
            title: '警告',
            content: '确认要删除该部门吗？',
            onOk: async () => {
              const res = await deleteOrg({ id: party[UserPickerOptions.id] })
              if (res.code === 'sso.ok') {
                this.$message.success(res.message)
                // 删除成功后，默认选中父节点
                this.onSelectTreeNode([party[UserPickerOptions.pid]], {
                  node: { dataRef: getNodeById(this.treeData, 'id', party[UserPickerOptions.pid]) }
                })
                this.getAllParty()
              }
            }
          })
          break
        case 'moveup':
          this.$confirm({
            title: '警告',
            content: '确认要上移该部门吗？',
            onOk: async () => {
              const res = await moveUpOrg({ id: party[UserPickerOptions.id] })
              console.log(res)
              if (res.code === 'sso.ok') {
                this.$message.success(res.message)
                this.getAllParty()
              }
            }
          })
          break
        case 'movedown':
          this.$confirm({
            title: '警告',
            content: '确认要下移该部门吗？',
            onOk: async () => {
              const res = await moveDownOrg({ id: party[UserPickerOptions.id] })
              if (res.code === 'sso.ok') {
                this.$message.success(res.message)
                this.getAllParty()
              }
            }
          })
          break
      }
    },
    /**
     * 新建编辑部门
     * @param {Number} parentId 上级部门id
     */
    handleOrgSubmit (parentIds) {
      if (parentIds.length) {
        // 添加部门后，默认展开父节点
        const idSet = new Set([...this.expandedKeys, ...parentIds])
        this.expandedKeys = Array.from(idSet)
      }
      this.getAllParty()
    },
    // 选中部门
    onSelectTreeNode (selectedKeys, node) {
      // 节点不可清除
      if (selectedKeys.length === 0) return
      this.selectedOrg = selectedKeys
      this.selectedOrgName = node && node.node.dataRef.name
      this.$refs.table.clearSelected()
      this.$refs.table.refresh(true)
    },
    // 重置查询参数
    resetSearch () {
      this.queryParams = { ...initialqueryParams }
      this.$refs.table.refresh(true)
    },
    // 列表勾选变化
    onSelectChange (selectedRowKeys, selectedRows) {
      this.selectedRowKeys = selectedRowKeys
      this.selectedRows = selectedRows
    },
    // 批量操作人员
    handleUserActions ({ key }) {
      const isSingle = this.selectedRowKeys.length === 1
      const descWord = isSingle ? '该' : '这些'

      switch (key) {
        case 'quit':
          this.$confirm({
            title: '警告',
            content: `确认需要离职${descWord}员工吗？`,
            onOk: async () => {
              this.handleQuitUsers(this.selectedRowKeys)
            }
          })
          break
        case 'delete':
          this.$confirm({
            title: '警告',
            content: `确认要删除${descWord}人员吗？`,
            onOk: async () => {
              this.handleDeleteUsers(this.selectedRowKeys.join())
            }
          })
          break
        case 'password':
          this.$confirm({
            title: '警告',
            content: `确认要重置${descWord}人员的密码吗？`,
            onOk: async () => {
              this.handleRestPassword(this.selectedRowKeys)
            }
          })
          break
        case 'move':
          this.$confirm({
            title: '警告',
            content: `确认要移动${descWord}人员吗？`,
            onOk: async () => {
              this.$refs.userMove.open(this.selectedRowKeys)
            }
          })
          break
        default:
          break
      }
    },
    /**
     * 删除人员
     * @param {String} ids 1,2,3
     */
    async handleDeleteUsers (ids) {
      const res = await deleteUser({ ids })
      if (res.code === 'sso.ok') {
        this.$message.success(res.message)
        this.handleClearBatch()
      }
    },
    /**
     * 离职人员
     * @param {Array} id
     */
    async handleQuitUsers (id) {
      const res = await quitUser({ id })
      if (res.code === 'sso.ok') {
        this.$message.success(res.message)
        this.handleClearBatch()
      }
    },
    /**
     * 重置密码
     * @param {Array} id
     */
    async handleRestPassword (id) {
      const res = await resetUserPassword({ id })
      if (res.code === 'sso.ok') {
        this.$message.success(res.message)
        this.handleClearBatch(false)
      }
    },
    // 下载导入模板
    async downloadExcelTemplate () {
      downloadFile('./templates/组织架构导入模板.xlsx', '组织架构导入模板.xlsx')
    },
    // 监听上传状态, 获取初步导入结果
    handleUpload (info) {
      const { status } = info.file
      if (status === 'uploading') {
        this.uploading = true
      } else if (status === 'done') {
        this.uploading = false
        const { response } = info.file
        this.$refs.importResultModal.show({ ...response.data, targetId: this.selectedOrg[0] })
      } else if (status === 'error') {
        this.uploading = false
      }
    },
    // 上传 Excel
    async customRequest ({ file, filename, onSuccess, onError }) {
      const formData = new FormData()
      formData.append(filename, file)
      formData.append('orgId', this.selectedOrg[0])
      const res = await importUsers(formData)
      if (res.code === 'sso.ok') {
        onSuccess(res)
      } else {
        onError()
      }
    },
    // 批量上传成功
    handleImportSuccess () {
      this.getAllParty()
      this.$refs.table.refresh(true)
    },
    // 批量导出人员
    async handleExportUsers () {
      this.exporting = true
      const res = await exportUsers({
        orgId: this.selectedOrg[0],
        ...this.queryParams
      })
      this.exporting = false
      downloadFileStream(res, '组织架构导出.xlsx')
    },
    // 批量操作成功后，清除数据
    handleClearBatch (refresh = true) {
      this.selectedRowKeys = []
      this.selectedRows = []
      if (refresh) this.$refs.table.refresh()
      // STable 需要主动调用 clearSelected 方法，清空勾选项
      this.$refs.table.clearSelected()
    },
    // 新建人员
    handleCreateUser () {
      if (!this.tableLoaded) return
      this.$router.push({
        name: 'structureUser',
        query: { orgId: this.selectedOrg[0], orgName: this.selectedOrgName }
      })
    },
    // 编辑人员
    handleUpdateUser (id) {
      this.$router.push({ name: 'structureUser', params: { id } })
    },
    // 排序人员
    handleSortUser (id, serialNum) {
      this.$refs.userSort.open(id, serialNum)
    },
    // 设置表格字段显示
    async handleFields (fields) {
      const res = await updateTableFields({
        fields,
        table: 'mos_user'
      })
      if (res.code === 'sso.ok') {
        this.visibleFields = fields
        this.$refs.fieldConfig.close()
      }
    }
  },
  beforeRouteEnter (to, from, next) {
    if (['structureUser', 'structureUserInfo'].includes(from.name)) {
      next(vm => {
        vm.expandedKeys = vm.$store.state.structure.expandedKeys
        vm.selectedOrg = vm.$store.state.structure.selectedKeys
        vm.selectedOrgName = vm.$store.state.structure.selectedOrgName
        vm.$store.commit('structure/set_expanded_keys', [])
        vm.$store.commit('structure/set_selected_keys', [])
        vm.$store.commit('structure/set_selected_name', '')
      })
    } else {
      next()
    }
  },
  beforeRouteLeave (to, from, next) {
    if (['structureUser', 'structureUserInfo'].includes(to.name)) {
      this.$store.commit('structure/set_expanded_keys', this.expandedKeys)
      this.$store.commit('structure/set_selected_keys', this.selectedOrg)
      this.$store.commit('structure/set_selected_name', this.selectedOrgName)
      next()
    } else {
      next()
    }
  }
}
</script>
